package website.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import website.constants.Code;
import website.domain.ResModel;
import website.domain.User;
import website.domain.WebInfo;
import website.dto.UserDTO;
import website.mapper.UserMapper;
import website.service.UserService;
import website.service.WebService;
import website.utils.*;

import javax.annotation.Resource;
import java.time.Duration;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static website.constants.RedisConstants.EMAIL_CODE_KEY;
import static website.constants.RedisConstants.USER_TOKEN_KEY;

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Resource
    private UserMapper userMapper;

    @Autowired
    private WebService webService;

    @Value("${profile.uid}")
    private Integer uid;
    /**
     * 注册
     * @param user
     * @return
     */
    @Override
    public ResModel register(User user) {
        if(user.getCode()!=null){
            if (user.getEmail()!=null && user.getPassword()!=null){
                String s = redisTemplate.opsForValue().get(EMAIL_CODE_KEY+user.getEmail());
                if (s!=null && s.equals(user.getCode())){
                    LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
                    wrapper.eq(true,User::getEmail,user.getEmail());
                    User one = getOne(wrapper);
                    if (one!=null){
                        return ResModel.error(Code.REGISTERED);
                    }
                    String salt = NowDateUtils.getSalt();
                    String encryption = MD5Utils.encryption(user.getPassword() + salt);
                    user.setSalt(salt);
                    user.setPassword(encryption);
                    user.setRegistrationTime(NowDateUtils.getNowDate());
                    boolean save = save(user);
                    return ResModel.success(Code.REGISTRATION,save);
                }else {
                    return ResModel.error(Code.CHECK_CODE_ERROR);
                }
            }
        }
        return ResModel.error(Code.FAIL);
    }

    /**
     * 登录
     * @param user
     * @return
     */
    @Override
    public ResModel login(User user) {
        if (user.getEmail()!=null && user.getPassword()!=null){
            LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(true,User::getEmail,user.getEmail());
            User one = getOne(wrapper);
            if (one==null){
                return ResModel.error(Code.UNREGISTERED);
            }
            String encryption = MD5Utils.encryption(user.getPassword() + one.getSalt());
            if (encryption.equals(one.getPassword())){
                one.setPassword(null);
                one.setSalt(null);
                /** 获取token */
                String token = JwtUtils.createJWT(one.getEmail(), 3600 * 24);
                one.setToken(token);
                UserDTO userDTO = BeanUtil.copyProperties(one, UserDTO.class);
                Map<String, Object> userMap = BeanUtil.beanToMap(userDTO, new HashMap<>(),
                        CopyOptions.create()
                                .setIgnoreNullValue(true)
                                .setFieldValueEditor((fieldName, fieldValue) -> fieldValue.toString()));
                redisTemplate.opsForHash().putAll(USER_TOKEN_KEY+token,userMap);
                redisTemplate.expire(USER_TOKEN_KEY+token,Duration.ofMinutes(30));
                return ResModel.success(Code.LOGIN,one);
            }
            return ResModel.error(Code.UN_LOGIN);
        }
        return ResModel.error(Code.FAIL);
    }

    /**
     * 获取邮箱验证码
     * @param user
     * @return
     */
    @Override
    public ResModel getCode(User user) {
        if (user.getEmail()!=null){
            String code = NowDateUtils.getSalt();
            redisTemplate.opsForValue().set(EMAIL_CODE_KEY + user.getEmail(),code, Duration.ofMinutes(10));
            EmailUtils emailUtils = new EmailUtils(user.getEmail(),code);
            emailUtils.run();
            return ResModel.success(Code.SUCCESS,null);
        }else {
            return ResModel.error(Code.EMAIL_NULL);
        }
    }

    /**
     * 修改用户信息
     * @param user
     * @return
     */
    @Override
    public ResModel updateUser(User user) {
        if (user.getUid()!=null){
            int i = userMapper.updateUserInfo(user);
            return ResModel.success(Code.UPDATE,i);
        }else {
            return ResModel.error(Code.UN_UPDATE);
        }
    }

    /**
     * 上传头像
     * @param file
     * @return
     */
    @Override
    public ResModel upload(MultipartFile file) {
        String s = UploadPicUtils.uploadPicture(file);
        return ResModel.success(Code.SUCCESS,s);
    }

    /**
     * 忘记密码
     * @param user
     * @return
     */
    @Override
    public ResModel forget(User user) {
        if(user.getCode()!=null){
            if (user.getEmail()!=null && user.getPassword()!=null){
                String s = redisTemplate.opsForValue().get(EMAIL_CODE_KEY+user.getEmail());
                if (s!=null && s.equals(user.getCode())){
                    LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
                    wrapper.eq(true,User::getEmail,user.getEmail());
                    User one = getOne(wrapper);
                    if (one!=null){
                        String salt = NowDateUtils.getSalt();
                        String encryption = MD5Utils.encryption(user.getPassword() + salt);
                        one.setSalt(salt);
                        one.setPassword(encryption);
                        int i = userMapper.forgetPassword(one);
                        return ResModel.success(Code.UPDATE,i);
                    }
                    return ResModel.error(Code.UNREGISTERED);
                }else {
                    return ResModel.error(Code.CHECK_CODE_ERROR);
                }
            }
        }
        return ResModel.error(Code.FAIL);
    }

    /**
     * 查询我的信息
     * @return
     */
    @Override
    public ResModel<User> getMyInfo() {
        User user = userMapper.getByUid(uid);
        user.setSalt(null);
        user.setPassword(null);
        //更新网站浏览量
        webService.update().setSql("visits = visits + 1").update();
        return ResModel.success(Code.SUCCESS,user);
    }

    /**
     * 查询用户信息
     * @param uid
     * @return
     */
    @Override
    public ResModel<User> getUserInfo(Integer uid) {
        if (uid!=null){
            User user = userMapper.getByUid(uid);
            user.setSalt(null);
            user.setPassword(null);
            return ResModel.success(Code.SUCCESS,user);
        }
        return ResModel.error(Code.FAIL);
    }

    /**
     * 分页查询用户信息
     * @param current
     * @param size
     * @param user
     * @return
     */
    @Override
    public ResModel<IPage<User>> getByPage(Integer current, Integer size, User user) {
        Page<User> page = new Page<>(current, size);
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.like(user.getNickname()!=null,User::getNickname,user.getNickname());
        Page<User> selectPage = userMapper.selectPage(page, wrapper);
        return ResModel.success(Code.SUCCESS,selectPage);
    }

    /**
     * 删除用户
     * @param uid
     * @return
     */
    @Override
    public ResModel delUser(Integer uid) {
        if (uid!=null){
            int i = userMapper.deleteByUid(uid);
            return ResModel.success(Code.DELETE,i);
        }
        return ResModel.error(Code.FAIL);
    }

    /**
     * 统计用户数量
     * @return
     */
    @Override
    public ResModel<Integer> getUserCount() {
        return ResModel.success(Code.SUCCESS,count());
    }

    /**
     * 用户排行榜
     * @return
     */
    @Override
    public ResModel<List<User>> getUserRank() {
        List<User> list = list();
        if (list.size()>6){
            ArrayList<User> users = new ArrayList<>();
            for (int i=0;i<6;i++) {
                users.add(list.get(i));
            }
            return ResModel.success(Code.SUCCESS,users);
        }
        return ResModel.success(Code.SUCCESS,list);
    }
}
